/*
	gpref.cc	GRhino Gnome Frontend Preferences Dialog Box
	Copyright (c) 2004, 2005, 2010 Kriang Lerdsuwanakij
	email:		lerdsuwa@users.sourceforge.net

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
#define GNOME_DISABLE_DEPRECATED
#define GTK_DISABLE_DEPRECATED
*/

#include "config.h"

#include <gtk/gtk.h>
#include <gnome.h>

#include <pthread.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>

#include <exception>
#include <stdexcept>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <string>

#include "board.h"
#include "hash.h"
#include "alphabeta.h"
#include "opening.h"
#include "pattern.h"
#include "parity.h"
#include "book.h"
#include "game.h"
#include "gpref.h"
#include "gutil.h"

#include "gtstream.h"

/*************************************************************************
	Configurations - GNOME specific
*************************************************************************/

int toolbar_icon_size;
GtkIconSize toolbar_icon_map[NUM_TOOLBAR_ICON_SIZE] = {
	GTK_ICON_SIZE_SMALL_TOOLBAR, GTK_ICON_SIZE_LARGE_TOOLBAR 
};
const char *toolbar_icon_name[NUM_TOOLBAR_ICON_SIZE] = {
	N_("Small"), N_("Large")
};

/*************************************************************************
	Preferences dialog box signals
*************************************************************************/

GtkWidget *combo_player;
GtkWidget *combo_level;
GtkWidget *spin_depth;
GtkWidget *spin_winlossdraw;
GtkWidget *spin_exact;
GtkWidget *spin_randomness;
GtkWidget *combo_opening_var;

GtkWidget *check_hint_move;
GtkWidget *check_show_last_move;
GtkWidget *check_show_border;
GtkWidget *check_log_move;
GtkWidget *check_redo_ai_move;
GtkWidget *combo_start_mode;
GtkWidget *combo_opening;
GtkWidget *spin_start_pieces;
GtkWidget *combo_theme;
GtkWidget *combo_toolbar_icon_size;
GtkWidget *check_animate_opening;
GtkWidget *spin_animate_delay;

void update_menu_and_toolbar_pref();

void preferences_closed(GtkWidget *widget, GtkWidget **data)
{
	gtk_widget_destroy(widget);
	*data = NULL;
}

void preferences_apply(GnomePropertyBox * /*propertybox*/, gint page, gpointer /*data*/)
{
	if (page >= 0)
		return;

					// Prevent running AI thread twice
	cancel_input();

	bool need_draw_board = false;
	bool need_load_theme = false;
	bool need_new_game = false;

	std::string entry = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_player)->entry));
	for (int i = 0; i < NUM_GAME_MODE; ++i) {
		if (entry == _(game_mode_name[i])) {
			game_mode_type new_mode = static_cast<game_mode_type>(i);

			if (new_mode != get_game_mode()) {
				maybe_set_ai_tampered();
				set_game_mode(new_mode);
			}
			break;
		}
	}

	entry = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_level)->entry));
	for (int i = 0; i < NUM_LEVEL_INFO+1; ++i) {
		if (entry == _(level_name[i])) {
			computer_level = i;
			break;
		}
	}

	int midgame_depth;
	int num_empty_winlossdraw;
	int num_empty_exact;

	if (computer_level == LEVEL_CUSTOM) {
		midgame_depth =
			gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_depth));
		num_empty_winlossdraw =
			gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_winlossdraw));
		num_empty_exact =
			gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_exact));
	}
	else {
		midgame_depth = level_info[computer_level].midgame_depth;
		num_empty_winlossdraw = level_info[computer_level].num_empty_winlossdraw;
		num_empty_exact = level_info[computer_level].num_empty_exact;
	}

	int randomness = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_randomness));

	entry = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_opening_var)->entry));
	for (int i = 0; i < NUM_OPENING_VAR; ++i) {
		if (entry == _(opening_var_name[i])) {
			if (opening_var != i)
				maybe_set_ai_tampered();

			opening_var = i;
			break;
		}
	}
	set_book_random(opening_var);

			// Flush hashed data if necessary
	if (current_level_info.midgame_depth != midgame_depth
	    || current_level_info.num_empty_winlossdraw != num_empty_winlossdraw
	    || current_level_info.num_empty_exact != num_empty_exact
	    || randomness != get_eval_random()) {
		free_hash_all_move();
		maybe_set_ai_tampered();
	}

			// Change parameters
	current_level_info.midgame_depth = midgame_depth;
	current_level_info.num_empty_winlossdraw = num_empty_winlossdraw;
	current_level_info.num_empty_exact = num_empty_exact;
	set_eval_random(randomness);

	log_move = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_log_move));
	redo_ai_move = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_redo_ai_move));

	bool old_animate_opening = animate_opening;
	animate_opening = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_animate_opening));

	animate_delay = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_animate_delay));

	entry = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_start_mode)->entry));
	for (int i = 0; i < NUM_START_GAME_MODE; ++i) {
		if (entry == _(start_game_mode_name[i])) {
			start_game_mode = static_cast<start_game_mode_type>(i);
			break;
		}
	}

	start_random_game_pieces = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_start_pieces));

	entry = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_opening)->entry));
        if (entry != _(opening_name.c_str()) || old_animate_opening != animate_opening) {
		for (int i = 0; i < get_num_opening(); ++i) {
			if (entry == _(get_opening_name(i))) {
				opening_name = get_opening_name(i);
				get_opening_move_sequence(i, opening_move_queue);
				break;
			}
		} 

		if (view_mode == VIEW_MODE_NONE) {
		        need_draw_board = true;
					// Check if all moves are AI's
                        int	i = cur_game_info.num_history;

					// Skip AI's turns
                        while (i > cur_game_info.min_num_history && is_computer_player(cur_game_info.player_history[i-2]))
			        i--;
                        if (i == cur_game_info.min_num_history)
			        need_new_game = true;
                }
	}

			// Add/remove hints if necessary
	bool old_hint_move = hint_move;
	hint_move = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_hint_move));
	if (hint_move != old_hint_move) {
		need_load_theme = true;
		need_draw_board = true;
	}

			// Add/remove hints if necessary
	bool old_show_last_move = show_last_move;
	show_last_move = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_show_last_move));
	if (show_last_move != old_show_last_move) {
		need_load_theme = true;
		need_draw_board = true;
	}

			// Add/remove border if necessary
	bool old_show_border = show_border;
	show_border = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_show_border));
	if (show_border != old_show_border) {
		need_load_theme = true;
		need_draw_board = true;
	}

	std::string old_theme_name = theme_name;
	entry = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_theme)->entry));
	if (entry == _("DEFAULT"))
		entry = "";
	if (theme_name != entry) {
		theme_name = entry;
		need_load_theme = true;
		need_draw_board = true;
	}

	entry = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_toolbar_icon_size)->entry));
	for (int i = 0; i < NUM_TOOLBAR_ICON_SIZE; ++i) {
		if (entry == _(toolbar_icon_name[i])) {
			if (toolbar_icon_size != i) {
				need_load_theme = true;
				toolbar_icon_size = i;
			}
			break;
		}
	}

	if (need_load_theme) {
		try {
			if (theme_name.size())
				load_pixmaps(false);
			else
				load_pixmaps(true);
		}
		catch (std::exception &e) {
			gtstream bufstr;
			gtout(bufstr, _("Theme problem: %$.  Revert to previous theme settings."))
				<< e.what();

			error_message_box(bufstr);

					// Restore old options
			show_border = old_show_border;
			theme_name = old_theme_name;

			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_show_border), show_border);
			if (theme_name.size())
				gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_theme)->entry),
						   theme_name.c_str());
			else
				gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_theme)->entry),
						   _("DEFAULT"));

					// Reload old theme
			if (theme_name.size())
				load_pixmaps(false);
			else
				load_pixmaps(true);
		}
		resize_board_widget();
	}

	if (view_mode) {
		if (need_draw_board)
			draw_board();
		update_menu_and_toolbar_pref();
	}
	else if (need_new_game) {
		new_game();
					// This must come after need_load_theme
					// so that dimensions are properly computed
		update_menu_and_toolbar_pref();
	}
	else {
		if (need_draw_board)
			draw_board();
		update_move.update(UPDATE_NONE);	// In case computer player
						// is switched

					// This must come after need_load_theme
					// so that dimensions are properly computed
		update_menu_and_toolbar_pref();

		// FIXME: Update clock here

					// Need to start running clock
		if (cur_game_info.is_game_play()) {
			if (get_wait_player())
				human_move();
			else
				computer_move();
		}
	}
}

void preferences_set_depth()
{
	int level = 0;

	std::string entry = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_level)->entry));

	for (int i = 0; i < NUM_LEVEL_INFO+1; ++i) {
		if (entry == _(level_name[i])) {
			level = i;
			break;
		}
	}
	if (level != LEVEL_CUSTOM) {
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_depth),
					  level_info[level].midgame_depth);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_winlossdraw),
					  level_info[level].num_empty_winlossdraw);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_exact),
					  level_info[level].num_empty_exact);

		gtk_widget_set_sensitive(spin_depth, FALSE);
		gtk_widget_set_sensitive(spin_winlossdraw, FALSE);
		gtk_widget_set_sensitive(spin_exact, FALSE);
	}
	else {
		gtk_widget_set_sensitive(spin_depth, TRUE);
		gtk_widget_set_sensitive(spin_winlossdraw, TRUE);
		gtk_widget_set_sensitive(spin_exact, TRUE);
	}
}

void preferences_help(GnomePropertyBox * /*propertybox*/, gint page, gpointer /*data*/)
{
	if (page == 0)
		gnome_help_display("grhino.xml", "grhino-prefs-ai", 0);
	else if (page == 1)
		gnome_help_display("grhino.xml", "grhino-prefs-board", 0);
	else
		gnome_help_display("grhino.xml", "grhino-prefs-theme", 0);
}

void preferences_changed(GtkEditable * /*editable*/, gpointer data)
{
	gnome_property_box_changed(GNOME_PROPERTY_BOX(data));
}

void preferences_level_changed(GtkEditable * /*editable*/, gpointer data)
{
	preferences_set_depth();
	gnome_property_box_changed(GNOME_PROPERTY_BOX(data));
}

/*************************************************************************
	Preferences dialog box
*************************************************************************/

void preferences()
{
	static GtkWidget *propertybox = NULL;

	if (propertybox) {
		gtk_window_present(GTK_WINDOW(propertybox));
		return;
	}

	propertybox = gnome_property_box_new();
	gtk_window_set_title(GTK_WINDOW(propertybox), _("Preferences"));

				//
				// Setup first page
				//

	GtkWidget *vbox = gtk_vbox_new(TRUE, 5);
	gtk_widget_show(vbox);
	GtkWidget *page_label = gtk_label_new(_("AI"));
	gtk_widget_show(page_label);

	GtkWidget *hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	GtkWidget *label = gtk_label_new(_("Computer player"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	GList *options = NULL;
	for (int i = 0; i < NUM_GAME_MODE; ++i)
		options = g_list_append(options, const_cast<char *>(_(game_mode_name[i])));
	combo_player = gtk_combo_new();
	gtk_combo_set_popdown_strings(GTK_COMBO(combo_player), options);
	gtk_combo_set_value_in_list(GTK_COMBO(combo_player), TRUE, FALSE);
	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_player)->entry),
			   get_game_mode_string());
	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo_player)->entry), FALSE);
	g_signal_connect(G_OBJECT(GTK_COMBO(combo_player)->entry), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(combo_player);
	gtk_box_pack_start(GTK_BOX(hbox), combo_player, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Computer level"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	options = NULL;
	for (int i = 0; i < NUM_LEVEL_INFO+1; ++i)
		options = g_list_append(options, const_cast<char *>(_(level_name[i])));
	combo_level = gtk_combo_new();
	gtk_combo_set_popdown_strings(GTK_COMBO(combo_level), options);
	gtk_combo_set_value_in_list(GTK_COMBO(combo_level), TRUE, FALSE);
	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_level)->entry),
			   _(level_name[computer_level]));
	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo_level)->entry), FALSE);
	g_signal_connect(G_OBJECT(GTK_COMBO(combo_level)->entry), "changed",
			 G_CALLBACK(preferences_level_changed), propertybox);
	gtk_widget_show(combo_level);
	gtk_box_pack_start(GTK_BOX(hbox), combo_level, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Mid game search depth"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	GtkAdjustment *	adj_depth = GTK_ADJUSTMENT(gtk_adjustment_new(
			current_level_info.midgame_depth, 1.0, 20.0,
			1.0, 1.0, 1.0));
	spin_depth = gtk_spin_button_new(adj_depth, 1.0, 0);
	gtk_entry_set_editable(GTK_ENTRY(spin_depth), FALSE);
	g_signal_connect(G_OBJECT(spin_depth), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(spin_depth);
	gtk_box_pack_start(GTK_BOX(hbox), spin_depth, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Winning move search empties"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	adj_depth = GTK_ADJUSTMENT(gtk_adjustment_new(
			current_level_info.num_empty_winlossdraw, 1.0, 20.0,
			1.0, 1.0, 1.0));
	spin_winlossdraw = gtk_spin_button_new(adj_depth, 1.0, 0);
	gtk_entry_set_editable(GTK_ENTRY(spin_winlossdraw), FALSE);
	g_signal_connect(G_OBJECT(spin_winlossdraw), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(spin_winlossdraw);
	gtk_box_pack_start(GTK_BOX(hbox), spin_winlossdraw, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Perfect end game search empties"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	adj_depth = GTK_ADJUSTMENT(gtk_adjustment_new(
			current_level_info.num_empty_exact, 1.0, 20.0,
			1.0, 1.0, 1.0));
	spin_exact = gtk_spin_button_new(adj_depth, 1.0, 0);
	gtk_entry_set_editable(GTK_ENTRY(spin_exact), FALSE);
	g_signal_connect(G_OBJECT(spin_exact), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(spin_exact);
	gtk_box_pack_start(GTK_BOX(hbox), spin_exact, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Randomness"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	adj_depth = GTK_ADJUSTMENT(gtk_adjustment_new(
			get_eval_random(), 0.0, 10.0,
			1.0, 1.0, 1.0));
	spin_randomness = gtk_spin_button_new(adj_depth, 1.0, 0);
	gtk_entry_set_editable(GTK_ENTRY(spin_randomness), FALSE);
	g_signal_connect(G_OBJECT(spin_randomness), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(spin_randomness);
	gtk_box_pack_start(GTK_BOX(hbox), spin_randomness, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Open book variation"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	options = NULL;
	for (int i = 0; i < NUM_OPENING_VAR; ++i)
		options = g_list_append(options, const_cast<char *>(_(opening_var_name[i])));
	combo_opening_var = gtk_combo_new();
	gtk_combo_set_popdown_strings(GTK_COMBO(combo_opening_var), options);
	gtk_combo_set_value_in_list(GTK_COMBO(combo_opening_var), TRUE, FALSE);
	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_opening_var)->entry),
			   _(opening_var_name[opening_var]));
	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo_opening_var)->entry), FALSE);
	g_signal_connect(G_OBJECT(GTK_COMBO(combo_opening_var)->entry), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(combo_opening_var);
	gtk_box_pack_start(GTK_BOX(hbox), combo_opening_var, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	gnome_property_box_append_page(GNOME_PROPERTY_BOX(propertybox),
				       vbox, page_label);

				//
				// Setup second page
				//

	vbox = gtk_vbox_new(TRUE, 5);
	gtk_widget_show(vbox);
	page_label = gtk_label_new(_("Board"));
	gtk_widget_show(page_label);

	check_log_move = gtk_check_button_new_with_label(_("Log game moves"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_log_move), log_move);
	g_signal_connect(G_OBJECT(check_log_move), "toggled",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(check_log_move);
	gtk_box_pack_start(GTK_BOX(vbox), check_log_move, TRUE, TRUE, 2);

	check_redo_ai_move = gtk_check_button_new_with_label(_("Redo also repeat same AI moves"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_redo_ai_move), redo_ai_move);
	g_signal_connect(G_OBJECT(check_redo_ai_move), "toggled",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(check_redo_ai_move);
	gtk_box_pack_start(GTK_BOX(vbox), check_redo_ai_move, TRUE, TRUE, 2);

	check_animate_opening = gtk_check_button_new_with_label(_("Animate opening"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_animate_opening), animate_opening);
	g_signal_connect(G_OBJECT(check_animate_opening), "toggled",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(check_animate_opening);
	gtk_box_pack_start(GTK_BOX(vbox), check_animate_opening, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Animation delay"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	adj_depth = GTK_ADJUSTMENT(gtk_adjustment_new(
			animate_delay, 1.0, NUM_ANIMATE_DELAY,
			1.0, 1.0, 1.0));
	spin_animate_delay = gtk_spin_button_new(adj_depth, 1.0, 0);
	gtk_entry_set_editable(GTK_ENTRY(spin_animate_delay), FALSE);
	g_signal_connect(G_OBJECT(spin_animate_delay), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(spin_animate_delay);
	gtk_box_pack_start(GTK_BOX(hbox), spin_animate_delay, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Start game from"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	options = NULL;
	for (int i = 0; i < NUM_START_GAME_MODE; ++i)
		options = g_list_append(options, 
					const_cast<char *>(_(start_game_mode_name[i])));
	combo_start_mode = gtk_combo_new();
	gtk_combo_set_popdown_strings(GTK_COMBO(combo_start_mode), options);
	gtk_combo_set_value_in_list(GTK_COMBO(combo_start_mode), TRUE, FALSE);
	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_start_mode)->entry),
			   _(start_game_mode_name[start_game_mode]));
	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo_start_mode)->entry), FALSE);
	g_signal_connect(G_OBJECT(GTK_COMBO(combo_start_mode)->entry), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(combo_start_mode);
	gtk_box_pack_start(GTK_BOX(hbox), combo_start_mode, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(FALSE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Opening"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	options = NULL;
	for (int i = 0; i < get_num_opening(); ++i)
		options = g_list_append(options, 
					const_cast<char *>(_(get_opening_name(i))));
	combo_opening = gtk_combo_new();
	gtk_combo_set_popdown_strings(GTK_COMBO(combo_opening), options);
	gtk_combo_set_value_in_list(GTK_COMBO(combo_opening), TRUE, FALSE);
	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_opening)->entry),
			   opening_name.c_str());
	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo_opening)->entry), FALSE);
	g_signal_connect(G_OBJECT(GTK_COMBO(combo_opening)->entry), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(combo_opening);
	gtk_box_pack_start(GTK_BOX(hbox), combo_opening, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Random game pieces"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	adj_depth = GTK_ADJUSTMENT(gtk_adjustment_new(
			start_random_game_pieces, 4.0, 32.0,
			2.0, 2.0, 2.0));
	spin_start_pieces = gtk_spin_button_new(adj_depth, 1.0, 0);
	gtk_entry_set_editable(GTK_ENTRY(spin_start_pieces), FALSE);
	g_signal_connect(G_OBJECT(spin_start_pieces), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(spin_start_pieces);
	gtk_box_pack_start(GTK_BOX(hbox), spin_start_pieces, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	gnome_property_box_append_page(GNOME_PROPERTY_BOX(propertybox),
				       vbox, page_label);

				//
				// Setup third page
				//

	vbox = gtk_vbox_new(TRUE, 5);
	gtk_widget_show(vbox);
	page_label = gtk_label_new(_("Theme"));
	gtk_widget_show(page_label);

	check_hint_move = gtk_check_button_new_with_label(_("Show possible moves"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_hint_move), hint_move);
	g_signal_connect(G_OBJECT(check_hint_move), "toggled",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(check_hint_move);
	gtk_box_pack_start(GTK_BOX(vbox), check_hint_move, TRUE, TRUE, 2);

	check_show_last_move = gtk_check_button_new_with_label(_("Show last move"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_show_last_move), show_last_move);
	g_signal_connect(G_OBJECT(check_show_last_move), "toggled",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(check_show_last_move);
	gtk_box_pack_start(GTK_BOX(vbox), check_show_last_move, TRUE, TRUE, 2);

	check_show_border = gtk_check_button_new_with_label(_("Show board border"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_show_border), show_border);
	g_signal_connect(G_OBJECT(check_show_border), "toggled",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(check_show_border);
	gtk_box_pack_start(GTK_BOX(vbox), check_show_border, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Theme directory"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	options = NULL;
	options = g_list_append(options, 
				const_cast<char *>(_("DEFAULT")));
	DIR *dir = opendir(THEMEDIR);
	if (dir) {
		struct dirent *dir_entry;
		while ((dir_entry = readdir(dir)) != NULL) {
						// Skip . and ..
			if (strcmp(dir_entry->d_name, ".") != 0
			    && strcmp(dir_entry->d_name, "..") != 0) {
				std::string pathname = THEMEDIR;
				pathname.append(dir_entry->d_name);
				struct stat buf;
				if (stat(pathname.c_str(), &buf) == 0
				    && S_ISDIR(buf.st_mode)) {
					// Allocate new buffer to permanently
					// store option
					options = g_list_append(options, 
								g_strdup(dir_entry->d_name));
				}
			}
		}
		closedir(dir);
	}
	combo_theme = gtk_combo_new();
	gtk_combo_set_popdown_strings(GTK_COMBO(combo_theme), options);
	gtk_combo_set_value_in_list(GTK_COMBO(combo_theme), TRUE, FALSE);
	if (theme_name.size())
		gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_theme)->entry),
				   theme_name.c_str());
	else
		gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_theme)->entry),
				   _("DEFAULT"));
	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo_theme)->entry), FALSE);
	g_signal_connect(G_OBJECT(GTK_COMBO(combo_theme)->entry), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(combo_theme);
	gtk_box_pack_start(GTK_BOX(hbox), combo_theme, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	hbox = gtk_hbox_new(TRUE, 5);
	gtk_widget_show(hbox);
	label = gtk_label_new(_("Toolbar icon size"));
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2);
	options = NULL;
	for (int i = 0; i < NUM_TOOLBAR_ICON_SIZE; i++)
		options = g_list_append(options, 
					const_cast<char *>(_(toolbar_icon_name[i])));
	combo_toolbar_icon_size = gtk_combo_new();
	gtk_combo_set_popdown_strings(GTK_COMBO(combo_toolbar_icon_size), options);
	gtk_combo_set_value_in_list(GTK_COMBO(combo_toolbar_icon_size), TRUE, FALSE);
	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_toolbar_icon_size)->entry),
			   _(toolbar_icon_name[toolbar_icon_size]));
	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo_toolbar_icon_size)->entry), FALSE);
	g_signal_connect(G_OBJECT(GTK_COMBO(combo_toolbar_icon_size)->entry), "changed",
			 G_CALLBACK(preferences_changed), propertybox);
	gtk_widget_show(combo_toolbar_icon_size);
	gtk_box_pack_start(GTK_BOX(hbox), combo_toolbar_icon_size, TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);

	gnome_property_box_append_page(GNOME_PROPERTY_BOX(propertybox),
				       vbox, page_label);

				//
				// Done with all pages
				//

	preferences_set_depth();

	g_signal_connect(G_OBJECT(propertybox), "apply",
			 G_CALLBACK(preferences_apply), NULL);
	g_signal_connect(G_OBJECT(propertybox), "help",
			 G_CALLBACK(preferences_help), NULL);
	g_signal_connect(G_OBJECT(propertybox), "destroy",
			 G_CALLBACK(preferences_closed), &propertybox);

	gtk_widget_show(propertybox);
}

